package processor;


import annotation.Id;
import annotation.Persistent;
import annotation.Property;
import com.google.auto.service.AutoService;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import java.util.LinkedHashSet;
import java.util.Set;

@AutoService(Processor.class)
public class MyAnnotationProcessor extends AbstractProcessor {

    /**
     * AbstractProcessor类中的init方法。一般来说直接继承不要进行其他修改。
     * 处理逻辑最好不要放在init中进行
     *
     * @param processingEnv 固定的输入变量--处理器环境
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        // TODO Auto-generated method stub
        super.init(processingEnv);
        System.out.println("MyAnnotationProcessor注解处理器初始化完成..............");
    }

    /**
     * 这里必须指定，这个注解处理器是注册给哪个注解使用的。注意，它的返回值是一个字符串的集合，包含本处理器想要处理的注解类型的全限定类名
     *
     * @return 注解器所支持的注解类型集合，如果没有这样的类型，则返回一个空集合
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        // 返回值是Set<String>
        Set<String> annotataions = new LinkedHashSet<String>();
        // 元注释名.class.getCanonicalName()--获取全限定类名
        annotataions.add(Id.class.getCanonicalName());
        annotataions.add(Property.class.getCanonicalName());
        annotataions.add(Persistent.class.getCanonicalName());
        return annotataions;
    }

    /**
     * 指定使用的Java版本，通常这里返回SourceVersion.latestSupported()，默认返回SourceVersion.RELEASE_6
     *
     * @return 使用的Java版本
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    /**
     * AbstractProcessor类中的process方法，用于编写处理逻辑。是注释处理器的核心
     *
     * @param annotations 固定的输入
     * @param roundEnv    固定的输入
     * @return 是否执行成功
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        try {
            // JSR269会在编译时在RoundEnvironment中自动维护一个所有注解的位置
            // 因此可以直接通过 RoundEnvironment.getElementsAnnotatedWith(Annotation.class)获取到所有目标注解的位置
            for (Element element : roundEnv.getElementsAnnotatedWith(Persistent.class)) {
                // 获取正在处理的元类信息
                // 注意Element本身就可以代表一种元素。因为Persistent注解是作用在TYPE上的，所以Element本身其实就是一个Class
                Name aClass = element.getSimpleName();

                // 这里得根据 @Persistent 作用在什么数据类型上来获取 @Persistent
                // 因为 @Persistent本身就是作用在 TYPE上，所以还是直接用aClass拿就行
                Persistent per = element.getAnnotation(Persistent.class);
                System.out.println("存在 @Persistent注解");
                System.out.println(per.country());

                //
                for (Element ele : element.getEnclosedElements()) {
                    //只处理成员变量上的Annotation，ele.getKind()返回所代表的的程序单元
                    if (ele.getKind() == ElementKind.FIELD) {
                        //被id注解修饰的字段
                        Id idAno = ele.getAnnotation(Id.class);
                        if (idAno != null) {
                            System.out.println("存在 @Id注解");
                            System.out.println(idAno.name());
                        }
                    }

                    if (ele.getKind() == ElementKind.METHOD) {
                        Property propertyAno = ele.getAnnotation(Property.class);
                        if (propertyAno != null) {
                            System.out.println("存在 @Property注解");
                            System.out.println(propertyAno.age());
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }
}
